using Google.Protobuf;
using System.Text;

namespace muduoDotNet
{
    /// <summary>
    /// Protobuf协议编解码器实现
    /// 使用4字节长度前缀 + Protobuf消息体的格式
    /// </summary>
    public class ProtobufCodec : IProtocolCodec
    {
        private const int kHeaderLen = 4; // 4字节消息长度头
        private const int kMaxMessageLen = 64 * 1024 * 1024; // 64MB最大消息长度

        /// <summary>
        /// 获取消息头长度
        /// </summary>
        public int HeaderLength => kHeaderLen;

        /// <summary>
        /// 将protobuf消息编码为字节数组
        /// 格式: [4字节长度][protobuf消息体]
        /// </summary>
        /// <param name="message">要编码的protobuf消息</param>
        /// <returns>编码后的字节数组</returns>
        public byte[] Encode(IMessage message)
        {
            if (message == null)
                throw new ArgumentNullException(nameof(message));

            try
            {
                // 序列化protobuf消息
                var messageData = message.ToByteArray();
                var messageLen = messageData.Length;

                if (messageLen > kMaxMessageLen)
                {
                    throw new NetException($"Message too large: {messageLen} bytes > {kMaxMessageLen} bytes");
                }

                // 创建包含长度头的完整消息
                var fullMessage = new byte[kHeaderLen + messageLen];
                
                // 写入消息长度（网络字节序，大端模式）
                fullMessage[0] = (byte)((messageLen >> 24) & 0xFF);
                fullMessage[1] = (byte)((messageLen >> 16) & 0xFF);
                fullMessage[2] = (byte)((messageLen >> 8) & 0xFF);
                fullMessage[3] = (byte)(messageLen & 0xFF);

                // 拷贝消息体
                System.Buffer.BlockCopy(messageData, 0, fullMessage, kHeaderLen, messageLen);

                Logger.Debug($"Encoded protobuf message: type={message.GetType().Name}, size={messageLen} bytes");
                return fullMessage;
            }
            catch (Exception ex)
            {
                Logger.Error($"Failed to encode protobuf message: {message.GetType().Name}", ex);
                throw new NetException("Failed to encode protobuf message", ex);
            }
        }

        /// <summary>
        /// 从缓冲区中解码protobuf消息
        /// </summary>
        /// <typeparam name="T">消息类型</typeparam>
        /// <param name="buffer">数据缓冲区</param>
        /// <param name="message">解码出的消息</param>
        /// <returns>如果成功解码返回true，否则返回false</returns>
        public bool TryDecode<T>(Buffer buffer, out T? message) where T : class, IMessage<T>, new()
        {
            message = null;

            try
            {
                // 检查是否有完整消息
                int messageLen = CheckMessageComplete(buffer);
                if (messageLen == -1)
                {
                    return false; // 消息不完整
                }

                // 跳过长度头
                buffer.Retrieve(kHeaderLen);

                // 读取消息体
                var messageData = buffer.RetrieveAsBytes(messageLen);

                // 解析protobuf消息
                var parser = new MessageParser<T>(() => new T());
                message = parser.ParseFrom(messageData);

                Logger.Debug($"Decoded protobuf message: type={typeof(T).Name}, size={messageLen} bytes");
                return true;
            }
            catch (InvalidProtocolBufferException ex)
            {
                Logger.Error($"Invalid protobuf message format for type {typeof(T).Name}", ex);
                return false;
            }
            catch (Exception ex)
            {
                Logger.Error($"Failed to decode protobuf message for type {typeof(T).Name}", ex);
                return false;
            }
        }

        /// <summary>
        /// 检查缓冲区中是否包含完整的消息
        /// </summary>
        /// <param name="buffer">数据缓冲区</param>
        /// <returns>如果包含完整消息返回消息长度，否则返回-1</returns>
        public int CheckMessageComplete(Buffer buffer)
        {
            if (buffer.ReadableBytes < kHeaderLen)
            {
                return -1; // 连长度头都没有
            }

            // 读取消息长度（网络字节序，大端模式）
            var headerData = buffer.PeekAsBytes(kHeaderLen);
            int messageLen = (headerData[0] << 24) | (headerData[1] << 16) | (headerData[2] << 8) | headerData[3];

            // 验证消息长度的合理性
            if (messageLen < 0 || messageLen > kMaxMessageLen)
            {
                Logger.Error($"Invalid message length: {messageLen}");
                throw new NetException($"Invalid message length: {messageLen}");
            }

            // 检查是否有完整的消息体
            if (buffer.ReadableBytes < kHeaderLen + messageLen)
            {
                return -1; // 消息不完整
            }

            return messageLen;
        }

        /// <summary>
        /// 尝试解码任意类型的protobuf消息
        /// </summary>
        /// <param name="buffer">数据缓冲区</param>
        /// <param name="messageType">消息类型</param>
        /// <param name="message">解码出的消息</param>
        /// <returns>如果成功解码返回true，否则返回false</returns>
        public bool TryDecodeAny(Buffer buffer, Type messageType, out IMessage? message)
        {
            message = null;

            try
            {
                // 检查是否有完整消息
                int messageLen = CheckMessageComplete(buffer);
                if (messageLen == -1)
                {
                    return false; // 消息不完整
                }

                // 跳过长度头
                buffer.Retrieve(kHeaderLen);

                // 读取消息体
                var messageData = buffer.RetrieveAsBytes(messageLen);

                // 创建消息实例
                if (Activator.CreateInstance(messageType) is not IMessage instance)
                {
                    Logger.Error($"Cannot create instance of message type: {messageType.Name}");
                    return false;
                }

                // 解析protobuf消息
                message = instance.Descriptor.Parser.ParseFrom(messageData);

                Logger.Debug($"Decoded protobuf message: type={messageType.Name}, size={messageLen} bytes");
                return true;
            }
            catch (InvalidProtocolBufferException ex)
            {
                Logger.Error($"Invalid protobuf message format for type {messageType.Name}", ex);
                return false;
            }
            catch (Exception ex)
            {
                Logger.Error($"Failed to decode protobuf message for type {messageType.Name}", ex);
                return false;
            }
        }
    }
}